use leptos::prelude::*;
use serde_json::Value;
use shq_common::prelude::{
    edit_props::EditProps, options::Options, Column, ControlType, DataType, Parameter, Size,
};

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct EditColumn {
    pub name: String,
    pub data_type: DataType,
    pub label: String,
    pub edit_props: EditProps,
}
impl EditColumn {
    pub fn new(
        name: String,
        data_type: DataType,
        label: String,
        edit_props: EditProps,
    ) -> EditColumn {
        EditColumn {
            name,
            data_type,
            label,
            edit_props,
        }
    }
    pub fn from_param_selected(
        name: &str,
        label: &str,
        multiple: bool,
        options: Vec<String>,
        default_value: Option<String>,
        grid: u8,
    ) -> Self {
        let edit_props = EditProps {
            control_type: ControlType::Select,
            init_val: default_value.map(|v| shq_common::prelude::DefaultValue::Str(v)),
            multiple,
            size: Size::SM,
            required: false,
            disabled: None,
            placeholder: None,
            tooltip: None,
            range_rule: None,
            regex_rule: None,
            grid,
            options: Some(Options::Array(options)),
            is_show_in_toolbar: false,
            is_editable: true,
        };
        Self::new(
            name.to_string(),
            DataType::String,
            label.to_string(),
            edit_props,
        )
    }
}
impl From<Parameter> for EditColumn {
    fn from(p: Parameter) -> Self {
        let edit_props = EditProps {
            control_type: p.edit_type,
            init_val: Some(shq_common::prelude::DefaultValue::Str(
                p.default_value.to_string(),
            )),
            multiple: p.multiple,
            size: Size::SM,
            required: false,
            disabled: None,
            placeholder: None,
            tooltip: None,
            range_rule: None,
            regex_rule: None,
            grid: p.grid,
            options: p.options,
            is_show_in_toolbar: false,
            is_editable: true,
        };
        Self::new(p.name, p.data_type, p.caption, edit_props)
    }
}
impl From<&Column> for EditColumn {
    fn from(c: &Column) -> Self {
        let mut ep = c.edit_props.clone().unwrap_or_default();
        ep.is_editable = true;
        Self::new(
            c.name.clone().unwrap_or_default(),
            c.data_type,
            c.title.clone().unwrap_or_default(),
            ep,
        )
    }
}
#[derive(Clone, Debug)]
pub struct ValueState {
    pub name: String,
    pub value: RwSignal<Value>,
    pub err_msg: RwSignal<Option<String>>,
}
impl ValueState {
    pub fn new(name: &str, value: RwSignal<Value>) -> Self {
        ValueState {
            name: name.to_string(),
            value,
            err_msg: RwSignal::new(None),
        }
    }
}
#[derive(Clone, Debug)]
pub struct EditRowState(Vec<ValueState>);
impl EditRowState {
    pub fn set_value(&mut self, name: &str, val: Value) {
        if let Some(signal) = self.0.iter().find(|s| s.name == name) {
            signal.value.set(val);
        } else {
            self.0.push(ValueState::new(name, RwSignal::new(val)));
        }
    }
    pub fn get_value(&self, name: &str) -> Option<RwSignal<Value>> {
        if let Some(signal) = self.0.iter().find(|s| s.name == name) {
            Some(signal.value)
        } else {
            None
        }
    }
    pub fn get_err_msg(&self, name: &str) -> Option<RwSignal<Option<String>>> {
        if let Some(signal) = self.0.iter().find(|s| s.name == name) {
            Some(signal.err_msg)
        } else {
            None
        }
    }
    pub fn set_err_msg(&self, name: &str, val: Option<String>) {
        if let Some(signal) = self.0.iter().find(|s| s.name == name) {
            signal.err_msg.set(val);
        }
    }
    pub fn from_columns(columns: &[EditColumn], param_vals: Vec<(String, String)>) -> Self {
        let mut vals: Vec<ValueState> = Vec::new();
        for c in columns {
            let pval = param_vals
                .iter()
                .find(|(k, _)| k == &c.name)
                .map(|(_, v)| v.clone());
            let val = if let Some(pval) = pval {
                Value::String(pval)
            } else {
                c.edit_props
                    .init_val
                    .as_ref()
                    .map(|v| v.to_string().into())
                    .unwrap_or(Value::Null)
            };
            let signal = RwSignal::new(val);
            vals.push(ValueState::new(&c.name, signal));
        }
        EditRowState(vals)
    }
    pub fn from_row_data(row_data: &Value) -> Self {
        let mut vals: Vec<ValueState> = Vec::new();
        if row_data.is_object() {
            for (k, v) in row_data
                .as_object()
                .expect("row_data必须是an object")
                .iter()
            {
                let signal = RwSignal::new(v.clone());
                vals.push(ValueState::new(&k, signal));
            }
        }
        EditRowState(vals)
    }
    pub fn iter(&self) -> impl Iterator<Item = &ValueState> {
        self.0.iter()
    }
}
